package com.szjz.freequery;

import com.szjz.freequery.util.FQUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * author:史博
 * date:2019/7/9
 * <p>
 * DynamicColumnQuery
 * 用于查询所有对象的任意列
 */
@Data
@Slf4j
@Component
public class FQList {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    private List<String> conditionList = new ArrayList<>();

    private Integer pageNum;

    private Integer pageSize;

    private Object object;

    private String tableName = null;

    private String tablePrefix = null;

    private PageModel pageModel = new PageModel();

    /**
     * where 后面的条件语句
     */
    public FQList addCondition(String condition) {
        conditionList.add(condition);
        return this;
    }

    /**
     * 指定表名前缀 如果添加了表前缀就不需要指定表名
     */
    public FQList tablePrefix(String tablePrefix) {
        if (tableName != null){
            throw new RuntimeException("表名已指定，请勿添加前缀");
        }
        this.tablePrefix = tablePrefix;
        return this;
    }

    /**
     * 指定表名前缀 如果指定了全表名 就不需要添加tablePrefix 防止重复
     */
    public FQList tableName(String tableName) {
        if (tablePrefix != null){
            throw new RuntimeException("已指定表前缀，请勿添加表名");
        }
        this.tableName = tableName;
        return this;
    }


    /**
     * 添加实体类
     */
    public FQList addObject(Object object) {
        this.object = object;
        return this;
    }

    /**
     * 添加页码
     */
    public FQList addPageNum(Integer pageNum) {
        this.pageNum = pageNum;
        return this;
    }

    /**
     * 添加每页大小
     */
    public FQList addPageSize(Integer pageSize) {
        this.pageSize = pageSize;
        return this;
    }

    /**
     * 获取执行查询之后的数据
     */
    public Object query() {
        return getData(object, pageNum, pageSize);
    }

    /**
     * 在Controller中直接调用此方法即可
     *
     * @param obj      实体类
     * @param pageNum  当前页
     * @param pageSize 每页大小
     * @return 分页或者列表数据
     */
    private Object getData(Object obj, Integer pageNum, Integer pageSize) {
        if (pageNum == null && pageSize == null) {
            pageModel.setPageNum(null);
            pageModel.setPageSize(null);
            List<Map<String, Object>> mapList = query(obj);
            // 成功之后移除条件集合内的条件
            conditionList.removeAll(conditionList);
            return mapList;
        } else {
            PageModel pageModel = query(obj, pageNum, pageSize);
            // 成功之后移除条件集合内的条件
            conditionList.removeAll(conditionList);
            return pageModel;
        }
    }

    /**
     * 列表查询 不分页
     */
    private List<Map<String, Object>> query(Object obj) {

        Class clazz = obj.getClass();
        //获取列名集合
        List<String> fieldNames = FQUtil.getFieldNames(obj);
        //创建sql
        String sql = createSql(fieldNames, clazz);
        //执行查询
        List<Map<String, Object>> mapList = FQUtil.queryCol(sql, jdbcTemplate);
        return mapList;
    }

    /**
     * 分页查询
     */
    private PageModel query(Object obj, Integer pageNum, Integer pageSize) {
        Assert.notNull(pageNum, "请输入起始页");
        Assert.notNull(pageSize, "请输入每页大小");
        //设置起始页，每页大小
        pageModel.setPageNum(pageNum);
        pageModel.setPageSize(pageSize);
        //执行查询，获取当前页内容
        List<Map<String, Object>> mapList = query(obj);
        //设置分页内容
        pageModel.setRows(mapList);
        //设置总元素数量
        StringBuffer sql = new StringBuffer("SELECT count(*) FROM ");
        String tableName = FQUtil.humpToUnderlineNaming(obj.getClass().getSimpleName());
        sql.append(this.tableName == null ? tableName : this.tableName);
        //添加where条件
        if (conditionList.size() > 0 && conditionList != null) {
            sql.append(" WHERE ");
            for (int i = 0; i < conditionList.size(); i++) {
                sql.append(conditionList.get(i));
                if (i != conditionList.size() - 1) {
                    sql.append(" AND ");
                }
            }
        }
        log.debug("【FQ】query count SQL: {}", sql);
        List<Map<String, Object>> maps = jdbcTemplate.queryForList(new String(sql));
        Long totalCount = Long.valueOf(maps.get(0).get("count(*)").toString());
        pageModel.setTotalCount(totalCount);
        //计算总页数
        Long totalPage = totalCount / pageSize + (totalCount % pageSize == 0 ? 0 : 1);
        pageModel.setTotalPage(Integer.valueOf(totalPage.toString()));
        //设置第一页最后一页
        pageModel.setIsFirst(pageNum == 0 ? true : false);
        pageModel.setIsLast(pageNum == totalPage - 1 ? true : false);
        log.debug("【FQ】query condition：{}",conditionList);

        return pageModel;
    }


    /**
     * 组装sql语句
     */
    private String createSql(List<String> colNameList, Class clazz) {
        //开始组装sql语句
        StringBuffer sql = new StringBuffer("SELECT ");
        //如果有列就查询对应的列
        if (colNameList.size() > 0 && colNameList != null) {
            for (int i = 0; i < colNameList.size(); i++) {
                Object name = colNameList.get(i);
                String underline = FQUtil.humpToUnderlineNaming(name.toString());
                sql.append(underline);
                if (colNameList.size() - 1 != i) {
                    sql.append(",");
                }
            }
        }
        //否则，就查询有效字段
        else {
            List<Field> allFields = new ArrayList<>();
            List<String> queriedFieldList = new ArrayList<>();

            List<Field> fields = Arrays.asList(clazz.getDeclaredFields());
            allFields = FQUtil.getValidFields(fields, allFields);
            allFields = FQUtil.addSuperFields(clazz, allFields);

            for (Field field : allFields) {
                String underline = FQUtil.humpToUnderlineNaming(field.getName());
                queriedFieldList.add(underline);
            }
            sql.append(StringUtils.join(queriedFieldList, ","));
        }
        sql.append(" FROM ");
        //添加表名(默认格式：***_***)
        String tableName = FQUtil.humpToUnderlineNaming(clazz.getSimpleName());
        if (tablePrefix != null) {
            tableName = tablePrefix + "_" + tableName;
        }
        sql.append(this.tableName == null ? tableName : this.tableName);

        //添加where条件
        if (conditionList.size() > 0 && conditionList != null) {
            sql.append(" WHERE ");
            for (int i = 0; i < conditionList.size(); i++) {
                sql.append(conditionList.get(i));
                if (i != conditionList.size() - 1) {
                    sql.append(" AND ");
                }
            }
        }

        //添加分页限制
        if (pageModel.getPageNum() != null && pageModel.getPageSize() != null) {
            sql.append(" limit " + pageModel.getPageNum() * pageModel.getPageSize() + " , " + pageModel.getPageSize());
        }
        log.debug("【FQ】query SQL：{}", sql);
        return new String(sql);
    }


    /**
     * 内部类：分页模型
     */
    @Data
    private class PageModel<T> {

        /**
         * 总个数
         */
        private Long totalCount;

        /**
         * 总页数
         */
        private Integer totalPage;

        /**
         * 每页容量
         */
        private Integer pageSize;

        /**
         * 当前页
         */
        private Integer pageNum;

        /**
         * 每页内容
         */
        private List<T> rows;

        /**
         * 第一页
         */
        private Boolean isFirst;

        /**
         * 最后一页
         */
        private Boolean isLast;

    }

}
